﻿using Core.Utility.Attributes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace System
{
    /// <summary>
    /// 特性扩展助手类
    /// </summary>
    public static class AttributeExtendsionHelper
    {
        /// <summary>
        /// 获取MemberInfo的CustomAttribute
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit">如果要搜索此成员的继承链以查找属性，则为 true；否则为 false。 会忽略属性和事件的此参数。</param>
        /// <returns></returns>
        public static TAttribute[]? GetMemberInfoAttributes<TAttribute>(
            this Type type,
            bool inherit = true) where TAttribute : Attribute
        {
            return (TAttribute[]?)type?.GetCustomAttributes(typeof(TAttribute),inherit);
        }

        /// <summary>
        /// 获取MemberInfo的CustomAttribute
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit">如果要搜索此成员的继承链以查找属性，则为 true；否则为 false。 会忽略属性和事件的此参数。</param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static TAttribute? GetMemberInfoAttribute<TAttribute>(
            this Type type,
            TAttribute? defaultValue = default,
            bool inherit = true) where TAttribute : Attribute
        {
            return GetMemberInfoAttributes<TAttribute>(type,inherit)?.FirstOrDefault() ?? defaultValue;
        }


        /// <summary>        
        /// /// 获取所有属性的CustomAttribute
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit">如果要搜索此成员的继承链以查找属性，则为 true；否则为 false。 会忽略属性和事件的此参数。</param>
        /// <param name="bindingFlags"></param>
        /// <returns></returns>
        public static List<TAttribute> GetAllPropertyAttribute<TAttribute>(
            this Type type,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true) where TAttribute : Attribute
        {
            PropertyInfo[] properties = type.GetProperties(bindingFlags);
            List<TAttribute> attributeList = new List<TAttribute>();
            foreach(var property in properties)
            {
                var attribute = GetPropertyFirstAttribute<TAttribute>(type, property.Name, bindingFlags,inherit);
                if(attribute != null)
                {
                    attributeList.Add(attribute);
                }
            }
            return attributeList;
        }

        /// <summary>
        /// 获取属性的CustomAttribute
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit">如果要搜索此成员的继承链以查找属性，则为 true；否则为 false。 会忽略属性和事件的此参数。</param>        
        /// <param name="propertyName"></param>
        /// <param name="bindingFlags"></param>        
        /// <returns></returns>
        public static TAttribute[]? GetPropertyAttribute<TAttribute>(
            this Type type,
            string propertyName, 
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true) where TAttribute : Attribute
        {
            return (TAttribute[]?)type
                .GetProperty(propertyName, bindingFlags )
                ?.GetCustomAttributes(typeof(TAttribute), inherit);
        }



        /// <summary>
        /// 获取属性的CustomAttribute
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit">如果要搜索此成员的继承链以查找属性，则为 true；否则为 false。 会忽略属性和事件的此参数。</param>
        /// <param name="propertyName"></param>
        /// <param name="bindingFlags"></param>
        /// <returns></returns>
        public static TAttribute? GetPropertyFirstAttribute<TAttribute>(
            this Type type,
            string propertyName,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true) where TAttribute : Attribute
        {
            return GetPropertyAttribute<TAttribute>(type,propertyName,bindingFlags,inherit)?.FirstOrDefault();
        }

        /// <summary>
        /// 获取方法的CustomAttribute
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit">如果要搜索此成员的继承链以查找属性，则为 true；否则为 false。 会忽略属性和事件的此参数。</param>
        /// <returns></returns>
        public static TAttribute[]? GetMethodAttribute<TAttribute>(
            this Type type,
            string methodName,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true) where TAttribute : Attribute, new()
        {
            return (TAttribute[]?)type
                .GetMethod(methodName, bindingFlags)
                ?.GetCustomAttributes(typeof(TAttribute), inherit);
        }



        /// <summary>
        /// 获取字段的CustomAttribute
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="type"></param>
        /// <param name="inherit">如果要搜索此成员的继承链以查找属性，则为 true；否则为 false。 会忽略属性和事件的此参数。</param>
        /// <param name="fieldName"></param>
        /// <param name="bindingFlags"></param>
        /// <returns></returns>
        public static TAttribute[]? GetFieldAttribute<TAttribute>(
            this Type type, 
            string fieldName, 
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true) where TAttribute : Attribute, new()
        {
            return (TAttribute[]?)type
                .GetField(fieldName, bindingFlags)
                ?.GetCustomAttributes(typeof(TAttribute), inherit);
        }

        /// <summary>
        /// 获取字段匹配中的第一个特性信息
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="sourceType">字段所在类的类型</param>
        /// <param name="fieldName">字段名称</param>
        /// <param name="bindingFlags"> 指定控制绑定以及通过反射执行成员和类型搜索的方式的标记。此枚举支持其成员值的按位组合。</param>
        /// <param name="inherit"></param>
        /// <returns></returns>
        public static TAttribute GetFieldFistAttribute<TAttribute>(
            this Type sourceType,
            string fieldName,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true)
            where TAttribute : Attribute, new()
        {
            //DisplayAttribute displayAttribute = new DisplayAttribute();
            TAttribute attribute = sourceType.GetFieldAttribute<TAttribute>(fieldName, bindingFlags, inherit)?.FirstOrDefault() ?? new TAttribute();
            return attribute;
        }

        /// <summary>
        /// 获取属性特性信息列表（指定类下的所有属性的第一个匹配中的特性）
        /// </summary>
        /// <returns></returns>
        public static List<AttributeInfo<TAttribute>> GetPropertyAttributeInfoList<TAttribute>(
            this Type type,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true)
            where TAttribute : Attribute, new()
        {
            List<AttributeInfo<TAttribute>> res = new List<AttributeInfo<TAttribute>>();
            var propertyList = type.GetProperties(bindingFlags);
            foreach(var item in propertyList)
            {
                res.Add(GetPropertyAttributeInfo<TAttribute>(type, item.Name, bindingFlags, inherit));
            }
            return res;
        }

        /// <summary>
        /// 获取属性特性信息列表（指定类下的所有属性的第一个匹配中的特性）
        /// </summary>
        /// <returns></returns>
        public static AttributeInfo<TAttribute> GetPropertyAttributeInfo<TAttribute>(
            this Type type,
            string propertyName,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true)
            where TAttribute : Attribute, new()
        {
            AttributeInfo<TAttribute> res = new AttributeInfo<TAttribute>();
            TAttribute attribute = type.GetPropertyAttribute<TAttribute>(propertyName, bindingFlags, inherit)?.FirstOrDefault() ?? new TAttribute();
            res.Attribute = attribute;
            res.AttributeSourceName = propertyName;
            res.AttributeSourceType = AttributeSourceTypeEnum.Property;
            res.AttributeName = nameof(TAttribute);
            res.DeclaringType = type;
            return res;
        }

        /// <summary>
        /// 获取字段特性信息列表（指定类下的所有字段的第一个匹配中的特性）
        /// </summary>
        /// <returns></returns>
        public static List<AttributeInfo<TAttribute>> GetFieldAttributeInfoList<TAttribute>(
            this Type type,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true)
            where TAttribute : Attribute, new()
        {
            List<AttributeInfo<TAttribute>> res = new List<AttributeInfo<TAttribute>>();
            var fieldList = type.GetFields(bindingFlags);
            foreach (var item in fieldList)
            {
                res.Add(GetFieldAttributeInfo<TAttribute>(type, item.Name, bindingFlags, inherit));
            }
            return res;
        }

        /// <summary>
        /// 获取字段特性信息列表（指定类下的所有字段的第一个匹配中的特性）
        /// </summary>
        /// <returns></returns>
        public static AttributeInfo<TAttribute> GetFieldAttributeInfo<TAttribute>(
            this Type type,
            string fieldName,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true)
            where TAttribute : Attribute, new()
        {
            AttributeInfo<TAttribute> res = new AttributeInfo<TAttribute>();
            TAttribute attribute = type.GetFieldAttribute<TAttribute>(fieldName, bindingFlags, inherit)?.FirstOrDefault() ?? new TAttribute();
            res.Attribute = attribute;
            res.AttributeSourceName = fieldName;
            res.AttributeSourceType = AttributeSourceTypeEnum.Field;
            res.AttributeName = nameof(TAttribute);
            res.DeclaringType = type;
            return res;
        }

        /// <summary>
        /// 获取方法特性信息列表（指定类下的所有方法的第一个匹配中的特性）
        /// </summary>
        /// <returns></returns>
        public static List<AttributeInfo<TAttribute>> GetMethodAttributeInfoList<TAttribute>(
            this Type type,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true)
            where TAttribute : Attribute, new()
        {
            List<AttributeInfo<TAttribute>> res = new List<AttributeInfo<TAttribute>>();
            var methodList = type.GetMethods(bindingFlags);
            foreach (var item in methodList)
            {
                res.Add(GetMethodAttributeInfo<TAttribute>(type, item.Name, bindingFlags, inherit));
            }
            return res;
        }

        /// <summary>
        /// 获取方法特性信息列表（指定类下的所有方法的第一个匹配中的特性）
        /// </summary>
        /// <returns></returns>
        public static AttributeInfo<TAttribute> GetMethodAttributeInfo<TAttribute>(
            this Type type,
            string methodName,
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic,
            bool inherit = true)
            where TAttribute : Attribute, new()
        {
            AttributeInfo<TAttribute> res = new AttributeInfo<TAttribute>();
            TAttribute attribute = type.GetMethodAttribute<TAttribute>(methodName, bindingFlags, inherit)?.FirstOrDefault() ?? new TAttribute();
            res.Attribute = attribute;
            res.AttributeSourceName = methodName;
            res.AttributeSourceType = AttributeSourceTypeEnum.Method;
            res.AttributeName = nameof(TAttribute);
            res.DeclaringType = type;
            return res;
        }

        /// <summary>
        /// 查找方法指定特性，如果没找到则继续查找声明类
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="method"></param>
        /// <param name="inherit"></param>
        /// <returns></returns>
        public static TAttribute? GetFoundAttribute<TAttribute>(this MethodInfo method, bool inherit)
            where TAttribute : Attribute
        {
            // 获取方法所在类型
            var declaringType = method.DeclaringType;

            var attributeType = typeof(TAttribute);

            // 判断方法是否定义指定特性，如果没有再查找声明类
            var foundAttribute = method.IsDefined(attributeType, inherit)
                ? method.GetCustomAttribute<TAttribute>(inherit)
                : (
                    declaringType?.IsDefined(attributeType, inherit) == true
                    ? declaringType.GetCustomAttribute<TAttribute>(inherit)
                    : default
                );

            return foundAttribute;
        }
    }
}
